package cn.wzptsoft.mall.config;

import cn.wzptsoft.mall.filter.JwtAuthenticaltionTokenFilter;
import cn.wzptsoft.mall.handler.*;

import cn.wzptsoft.mall.service.Impl.UserDetailsServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.ProviderManager;
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
import org.springframework.security.config.Customizer;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.csrf.CsrfFilter;
import org.springframework.security.web.session.DisableEncodeUrlFilter;

@Configuration
@EnableWebSecurity
public class SecurityConfig {

    @Autowired
    private UserDetailsServiceImpl userDetailsService;

    @Bean
    public AuthenticationManager authenticationManager(PasswordEncoder passwordEncoder) {
        DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
        //将编写的UserDetailsService注入进来
        provider.setUserDetailsService(userDetailsService);
        //将使用的密码编译器加入进来
        provider.setPasswordEncoder(passwordEncoder);
        //将provider放置到AuthenticationManager中
        ProviderManager providerManager = new ProviderManager(provider);
        return providerManager;
    }

    @Autowired
    private JwtAuthenticaltionTokenFilter jwtAuthenticaltionTokenFilter;

    @Autowired
    private CustomAuthenticationEntryPoint customAuthenticationEntryPoint;

    @Autowired
    private FilterChainExceptionHandler filterChainExceptionHandler;



    @Bean
    SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http
                .csrf(c -> c.disable())
                .sessionManagement(s -> s.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
                .exceptionHandling(e -> e.authenticationEntryPoint(customAuthenticationEntryPoint)
                        .accessDeniedHandler(new AccessDeniedHandler()))
                .authorizeHttpRequests(
                        requset -> requset.requestMatchers("/swagger**/**").permitAll()
                                .requestMatchers("/favicon.ico").permitAll()
                                .requestMatchers("/webjars/**").permitAll()
                                .requestMatchers("/v3/**").permitAll()
                                .requestMatchers("/doc.html").permitAll()
                                .requestMatchers("/user/login").anonymous()
//                                .requestMatchers("/spu/**").hasAnyAuthority("admin")
//                                .requestMatchers("/theme/**").hasRole("admin-plus")
                                .anyRequest()//其他路径都要进行拦截
                                .authenticated()  //已认证的请求会被授权
                )
                .formLogin(f->f.failureHandler(new AuthenticationFailure())
                        .successHandler(new AuthenticationSuccess())
                        )
                .logout(l->l.logoutSuccessHandler(new LogoutSuccessHandler()))
                .addFilterBefore(filterChainExceptionHandler, DisableEncodeUrlFilter.class)
                .addFilterBefore(jwtAuthenticaltionTokenFilter, UsernamePasswordAuthenticationFilter.class)
                .cors(Customizer.withDefaults())//解决跨域
        ;
        return http.build();
    }

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }


}
